package com.zyf.service;

import cn.hutool.core.io.FileUtil;
import com.zyf.service.audio.HandleAudioService;
import com.zyf.service.img.HandleImageMergeService;
import com.zyf.service.video.HandleVideoService;
import com.zyf.service.video.MakeVideoService;
import com.zyf.service.video.VedioUtils;
import com.zyf.tts.service.HandleTTSService;
import com.zyf.utils.FFmpegUtils;
import com.zyf.utils.HttpClientUtils;
import com.zyf.utils.StringUtil;
import org.bytedeco.javacv.FFmpegFrameGrabber;

import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 长视频处理类
 */
public class HandleLongVideoBP {
    private static final int MAXLENGTH = 1100;
    private static final String TTSURL = "http://192.168.1.2:9880";

    private static final String REFPATH = "./参考音频/[诗词]诗词.wav";

    private static final String REFTEXT = "明朝身不至,百忧非我所三乐事无事.";
    private List<String> initNumstrList = new ArrayList<>();
    private final String[] initNumstr = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十",
            "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
            "二十一", "二十二", "二十三", "二十四", "二十五", "二十六", "二十七", "二十八", "二十九", "三十",
            "三十一", "三十二", "三十三", "三十四", "三十五", "三十六", "三十七", "三十八", "三十九", "四十",
            "四十一", "四十二", "四十三", "四十四", "四十五", "四十六", "四十七", "四十八", "四十九", "五十",
            "五十一", "五十二", "五十三", "五十四", "五十五", "五十六", "五十七", "五十八", "五十九", "六十",
            "六十一", "六十二", "六十三", "六十四", "六十五", "六十六", "六十七", "六十八", "六十九", "七十",
            "七十一", "七十二", "七十三", "七十四", "七十五", "七十六", "七十七", "七十八", "七十九", "八十",
            "八十一", "八十二", "八十三", "八十四", "八十五", "八十六", "八十七", "八十八", "八十九", "九十",
            "九十一", "九十二", "九十三", "九十四", "九十五", "九十六", "九十七", "九十八", "九十九", "一百",
            "一百零一", "一百零二", "一百零三", "一百零四", "一百零五", "一百零六", "一百零七", "一百零八", "一百零九",
            "一百一十", "一百一十一", "一百一十二", "一百一十三", "一百一十四", "一百一十五", "一百一十六", "一百一十七",
            "一百一十八", "一百一十九", "一百二十", "一百二十一", "一百二十二", "一百二十三", "一百二十四", "一百二十五",
            "一百二十六", "一百二十七", "一百二十八", "一百二十九", "一百三十", "一百三十一", "一百三十二", "一百三十三",
            "一百三十四", "一百三十五", "一百三十六", "一百三十七", "一百三十八", "一百三十九", "一百四十",
            "一百四十一", "一百四十二", "一百四十三", "一百四十四", "一百四十五", "一百四十六", "一百四十七", "一百四十八",
            "一百四十九", "一百五十"};

    public HandleLongVideoBP() {
        initNumstrList = Arrays.asList(initNumstr);
    }

    /**
     * 制作单个的长视频
     */
    public void makeSingleVideo(String folderPath) throws Exception {
        List<File> txtList = FileUtil.loopFiles(folderPath, file -> file.isFile() && file.getName().endsWith(".txt"));
        List<File> backMp4List = FileUtil.loopFiles(folderPath, file -> file.isFile() && file.getName().endsWith(".mp4") && file.getName().contains("back"));
        //生成音频
        handleBatchTTSByTXT(txtList.get(0).getAbsolutePath());
        //合并音频
        String txtfilename = txtList.get(0).getName().substring(0, txtList.get(0).getName().indexOf("."));
        String audioFolderPath = folderPath + File.separator + txtfilename;
        String finalAudio = new VedioUtils().mergeMulAudiosByFFmpeg(audioFolderPath);
        //抓取内容视频的宽高
        FFmpegFrameGrabber grabberVideo = null;
        FFmpegFrameGrabber grabberAudio = null;
        int width = 1300;
        int height=1800;
        long durationAudio = 0;
        double frameRate = 0;
        int backWidth = 0;
        int backHeitht = 0;
        int coverWidth = 0;
        int coverHeitht = 0;
        try {
            //抓取视频帧
            grabberVideo = new FFmpegFrameGrabber(backMp4List.get(0).getAbsolutePath());
            grabberAudio = new FFmpegFrameGrabber(finalAudio);
            grabberVideo.start();
            grabberAudio.start();
            //获取时长,以短的文件为主进行截取
            long durationVideo = grabberVideo.getFormatContext().duration() / 1000000;
            durationAudio = grabberAudio.getFormatContext().duration() / 1000000;
            frameRate = grabberVideo.getFrameRate();
            backWidth = grabberVideo.getImageWidth();
            backHeitht = grabberVideo.getImageHeight();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (grabberVideo != null) {
                grabberVideo.stop();
                grabberVideo.release();
            }
        }
        String filename = txtList.get(0).getName();
        //将语音文件和背景音乐合成
        System.out.println("-----开始提取视频");
        String backsingleVideo = new VedioUtils().splitSingleVideo(backMp4List.get(0).getAbsolutePath());
        System.out.println("-----提取视频结束");
        String backFilal = "";
        if (backWidth > backHeitht) {
            //调整背景视频的分辨率
            System.out.println("-----开始调整背景视频分辨率");
            backFilal = new HandleVideoService().updateVideoRate(backsingleVideo, width, height);
            System.out.println("-----调整背景视频分辨率结束");
            coverWidth=width;
            coverHeitht=height;
        } else {
            if(backWidth>=width&&backHeitht>=height){
                backFilal = new HandleVideoService().updateVideoRate(backsingleVideo, width, height);
                coverWidth=width;
                coverHeitht=height;
            }else{
                coverWidth=backWidth;
                coverHeitht=backHeitht;
            }
        }
        //1.生成封面视频
        List<String> content = new ArrayList<>();
        String totalcontent = filename.substring(0, filename.indexOf("."));
        String[] splitList = totalcontent.split("第");
        for (char strchar : splitList[0].toCharArray()) {
            content.add(strchar + "");
        }
        content.add("第" + splitList[1]);
        String coverimg = new HandleImageMergeService().createCoverImgByContentByWidth(content, txtList.get(0).getAbsolutePath(),coverWidth,coverHeitht, 260);
        String firstMp4path = folderPath + File.separator + "first.mp4";
        MergeDataService.createMp4ByFFmpegAndFrameRate(firstMp4path, coverimg, coverWidth, coverHeitht, frameRate, 2);//默认2秒
        //2.嵌入视频
        List<String> files = new ArrayList<>();
        files.add(firstMp4path);

        //在分辨率1300x1800下,目前不存在横向嵌入视频
//        System.out.println("开始合成背景视频-----");
//        String secondMp4Savepath = folderPath + File.separator + "second.mp4";
//        MergeDataService.createMp4ByFFmpegAndBackDefault(secondMp4Savepath, width, 1800, 2);//默认2秒
//        System.out.println("-----合成背景视频结束");
//        System.out.println("开始嵌入视频-----");
//        embedMp4Savepath = new HandleVideoService().embedDoubleMp4ByDuration(secondMp4Savepath, backFilal);
//        System.out.println("-----嵌入视频结束");
        //延长背景视频
        String finalMp4 = new HandleVideoService().extendVideo(backFilal, (durationAudio - 2) + "");
        //合成两个视频  String recursionVideos(List<String> fileList)
        files.add(finalMp4);
        String finalMa4Path = new VedioUtils().recursionVideos(files);
        //合成音频
        System.out.println("开始合成视频和音频-----");
        String mp4path = new HandleVideoService().mergeVediosAndAudio(finalMa4Path, finalAudio);
        System.out.println("-----合成视频和音频结束");
        //生成字幕
        int fontLength=25;
        if(backWidth<width){
            fontLength=20;
        }
        String finalSrt = new HandleAudioService().generateSrtBySilence(finalAudio,txtList.get(0).getAbsolutePath(),fontLength);
        //合并视频和字幕
        new HandleVideoService().mergeVediosAndSrtByDoubleFile(mp4path, finalSrt);

    }

    /**
     * 根据txt合成语音
     */
    public void handleBatchTTSByTXT(String txtpath) throws Exception {
        //生成文件夹
        File txtfile = new File(txtpath);
        if (!txtfile.exists()) {
            throw new RuntimeException("文本不存在");
        }
        String filename = txtfile.getName().substring(0, txtfile.getName().indexOf("."));
        File foleder = new File(txtfile.getParent() + File.separator + filename);
        if (!foleder.exists()) {
            foleder.mkdir();
        }
        //解析文本
        String content = getSrcTxtByLine(txtpath);
        int total = content.length();
        int circle = total / MAXLENGTH + 1;
        String[] punctuation = {"。","？","！"};
        List<String> punctuations = Arrays.asList(punctuation);
        List<String> conlist = new ArrayList<>();
        for (int i = 0; i < circle; i++) {
            String res ="";
            //判断此句有几个停顿
            int flag = 0;
            if(content.length()>MAXLENGTH){
                int endindex= MAXLENGTH + 100;
                if(content.length()<=MAXLENGTH + 100){
                    endindex=content.length();
                }
                String match = content.substring(MAXLENGTH, endindex);
                for (char st : match.toCharArray()) {
                    String puncStr = st + "";
                    if (punctuations.contains(puncStr)) {
                        break;
                    } else {
                        flag++;
                    }
                }
                if (flag > 0) {
                    res = content.substring(0, MAXLENGTH + flag+1);
                }else{
                    res =  content.substring(0, MAXLENGTH+1);
                }
                content = content.substring(res.length());
            }else{
                res=content;
                content = content.substring(res.length());
            }
            if(!StringUtil.isBlank(res)){
                conlist.add(res);
                String finalsrt = foleder + File.separator + (i+1) + "_part.txt";
                writeFile(res, finalsrt);
            }
        }
        //遍历生成语音合成文件
        for (int i = 0; i < conlist.size(); i++) {
            handleSingleTTS(TTSURL, REFPATH, REFTEXT, conlist.get(i),foleder.getAbsolutePath());
        }
    }

    /**
     * 根据指定路径合成语音
     *  zh-CN-YunxiNeural
     * @return
     * @throws IOException
     */
    public void handleSingleTTS(String url, String refPath, String refText, String srcContent,String folder) throws Exception {
        //设置请求参数
        StringBuffer param=new StringBuffer();
        param.append("text="+ URLEncoder.encode(srcContent,"utf-8"));
        param.append("&text_lang=zh&");
        param.append("ref_audio_path="+ URLEncoder.encode(refPath,"utf-8"));
        param.append("&prompt_lang=zh&");
        param.append("prompt_text="+URLEncoder.encode(refText,"utf-8"));
        param.append("&text_split_method=cut5&batch_size=20&media_type=wav&speed_factor=1.0");

        HttpClientUtils.doGet(url,param.toString());
        //新文件夹路径
        String wavPath = "F:\\project\\GPT_SOVTTS\\GPT-SoVITS-v2\\音频输出\\audio.wav";
        String srtPath = "F:\\project\\GPT_SOVTTS\\GPT-SoVITS-v2\\音频输出\\tts-out.srt";
        //复制文件
        copyFile(wavPath, folder);
        copyFile(srtPath, folder);
    }

    private void copyFile(String sourceFile, String desfolder) {
        // 源文件路径
        Path source = Paths.get(sourceFile);
        // 目标文件夹路径
        Path destinationDir = Paths.get(desfolder);
        // 目标文件路径
        Path destination = destinationDir.resolve(source.getFileName());
        try {
            // 确保目标文件夹存在
            Files.createDirectories(destinationDir);
            // 使用Files.copy()方法复制文件到目标文件夹
            Files.copy(source, destination);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 读取源文件
     */
    public String getSrcTxtByLine(String filepath) throws FileNotFoundException {
        String[] punctuation = {"。", "，", "、", "；", "：", "？", "！", "•", ".","—"};
        List<String> punctuations = Arrays.asList(punctuation);
        StringBuffer buffer = new StringBuffer();
        InputStream inputstream = new FileInputStream(new File(filepath));
        BufferedReader reader = null;
        String temp = "";
        try {
            int index=0;
            reader = new BufferedReader(new InputStreamReader(inputstream));
            while ((temp = reader.readLine()) != null) {
                if(index==1){
                    for(int i=0;i<temp.toCharArray().length;i++){
                        String currStr=temp.toCharArray()[i]+"";
                        if(i>1){
                            if(!isChinese(currStr)&&!punctuations.contains(currStr)){
                                buffer.append("，");
                            }else{
                                buffer.append(currStr);
                            }
                        }else{
                            if(isChinese(currStr)||punctuations.contains(currStr)){
                                buffer.append(currStr);
                            }
                        }
                    }
                    buffer.append("。");
                }else{
                    for(char strChar:temp.toCharArray()){
                        String currStr=strChar+"";
                        if(isChinese(currStr)||punctuations.contains(currStr)){
                            buffer.append(currStr);
                        }
                    }
                }
                index++;
            }
        } catch (IOException e) {
            if (reader != null)
                try {
                    reader.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return buffer.toString();
    }


    public boolean isChinese(String str) {
        boolean isChinese = true;
        for (char c : str.toCharArray()) {
            if (!Character.isIdeographic(c)) {
                isChinese = false;
                break;
            }
        }
        return isChinese;
    }

    /**
     * 制作单个的长视频
     */
    public void makeSingleVideoBySingleTxt(String folderPath) throws Exception {
        List<File> txtList = FileUtil.loopFiles(folderPath, file -> file.isFile() && file.getName().endsWith(".txt"));
        List<File> backMp4List = FileUtil.loopFiles(folderPath, file -> file.isFile() && file.getName().endsWith(".mp4") && file.getName().contains("back"));
        //生成音频
        String finalAudio = new HandleTTSService().handleTTSByLimit(txtList.get(0).getAbsolutePath());
        File audioFile = new File(finalAudio);
        if (!audioFile.exists()) {
            throw new RuntimeException("音频未生成");
        }
        //抓取内容视频的宽高
        FFmpegFrameGrabber grabberVideo = null;
        FFmpegFrameGrabber grabberAudio = null;
        int width = 1300;
        int height=1800;
        long durationAudio = 0;
        double frameRate = 0;
        int backWidth = 0;
        int backHeitht = 0;
        int coverWidth = 0;
        int coverHeitht = 0;
        try {
            //抓取视频帧
            grabberVideo = new FFmpegFrameGrabber(backMp4List.get(0).getAbsolutePath());
            grabberAudio = new FFmpegFrameGrabber(finalAudio);
            grabberVideo.start();
            grabberAudio.start();
            //获取时长,以短的文件为主进行截取
            long durationVideo = grabberVideo.getFormatContext().duration() / 1000000;
            durationAudio = grabberAudio.getFormatContext().duration() / 1000000;
            frameRate = grabberVideo.getFrameRate();
            backWidth = grabberVideo.getImageWidth();
            backHeitht = grabberVideo.getImageHeight();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (grabberVideo != null) {
                grabberVideo.stop();
                grabberVideo.release();
            }
        }
        String filename = txtList.get(0).getName();
        //将
        System.out.println("-----开始提取视频");
        String backsingleVideo = new VedioUtils().splitSingleVideo(backMp4List.get(0).getAbsolutePath());
        System.out.println("-----提取视频结束");
        String backFilal = "";
        if (backWidth > backHeitht) {
            //调整背景视频的分辨率
            System.out.println("-----开始调整背景视频分辨率");
            backFilal = new HandleVideoService().updateVideoRate(backsingleVideo, width, height);
            System.out.println("-----调整背景视频分辨率结束");
            coverWidth=width;
            coverHeitht=height;
        } else {
            backFilal = backsingleVideo;
            coverWidth=backWidth;
            coverHeitht=backHeitht;
        }
        //1.生成封面视频
        List<String> content = new ArrayList<>();
        String totalcontent = filename.substring(0, filename.indexOf("."));
        String[] splitList = totalcontent.split("第");
        for (char strchar : splitList[0].toCharArray()) {
            content.add(strchar + "");
        }
        content.add("第" + splitList[1]);
        String coverimg = new HandleImageMergeService().createCoverImgByContent(content, txtList.get(0).getAbsolutePath(), 260);
        String firstMp4path = folderPath + File.separator + "first.mp4";
        MergeDataService.createMp4ByFFmpegAndFrameRate(firstMp4path, coverimg, coverWidth, coverHeitht, frameRate, 2);//默认2秒
        //2.嵌入视频
        List<String> files = new ArrayList<>();
        files.add(firstMp4path);
        //延长背景视频
        String finalMp4 = new HandleVideoService().extendVideo(backFilal, (durationAudio - 2) + "");
        //合成两个视频
        files.add(finalMp4);
        String finalMa4Path = new VedioUtils().recursionVideos(files);
        //合成音频
        System.out.println("开始合成视频和音频-----");
        String mp4path = new HandleVideoService().mergeVediosAndAudio(finalMa4Path, finalAudio);
        System.out.println("-----合成视频和音频结束");
        //生成字幕
        int fontLength=25;
        if(backWidth<width){
            fontLength=20;
        }
        String finalSrt = new HandleAudioService().generateSrtBySilence(finalAudio,fontLength);
        //合并视频和字幕
        new HandleVideoService().mergeVediosAndSrtByDoubleFile(mp4path, finalSrt);


    }

    /**
     * 制作名言录
     */
    public void makeFamousVideo(String folderPath) throws Exception {
        List<File> txtList = FileUtil.loopFiles(folderPath, file -> file.isFile() && file.getName().endsWith(".txt"));
        List<File> backMp4List = FileUtil.loopFiles(folderPath, file -> file.isFile() && file.getName().endsWith(".mp4") && file.getName().contains("back"));
        //生成音频
        String finalAudio = new HandleTTSService().handleTTSByLimit(txtList.get(0).getAbsolutePath());
        File audioFile = new File(finalAudio);
        if (!audioFile.exists()) {
            throw new RuntimeException("音频未生成");
        }
        //抓取内容视频的宽高
        FFmpegFrameGrabber grabberVideo = null;
        FFmpegFrameGrabber grabberAudio = null;
        int width = 1300;
        long durationAudio = 0;
        double frameRate = 0;
        try {
            //抓取视频帧
            grabberVideo = new FFmpegFrameGrabber(backMp4List.get(0).getAbsolutePath());
            grabberAudio = new FFmpegFrameGrabber(finalAudio);
            grabberVideo.start();
            grabberAudio.start();
            //获取时长,以短的文件为主进行截取
            long durationVideo = grabberVideo.getFormatContext().duration() / 1000000;
            durationAudio = grabberAudio.getFormatContext().duration() / 1000000;
            frameRate = grabberVideo.getFrameRate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (grabberVideo != null) {
                grabberVideo.stop();
                grabberVideo.release();
            }
        }
        String filename = txtList.get(0).getName();
        //将
        System.out.println("-----开始提取视频");
        String backsingleVideo = new VedioUtils().splitSingleVideo(backMp4List.get(0).getAbsolutePath());
        System.out.println("-----提取视频结束");
        //调整背景视频的分辨率
        System.out.println("-----开始调整背景视频分辨率");
        String backFilal = new HandleVideoService().updateVideoRate(backsingleVideo, width, 1800);
        System.out.println("-----调整背景视频分辨率结束");
        //延长背景视频
        String finalMp4 = new HandleVideoService().extendVideo(backFilal, durationAudio + "");
        //合成音频
        System.out.println("开始合成视频和音频-----");
        String mp4path = new HandleVideoService().mergeVediosAndAudio(finalMp4, finalAudio);
        System.out.println("-----合成视频和音频结束");
        //生成字幕
        String srtpath = new HandleAudioService().generateSrtBySilence(finalAudio,25);
        //合并字幕
        new HandleVideoService().batchMergeVediosBySrt(mp4path);
        //删除文件
    }

    public String mergeVediosAndAudio(String videoPath, String audioPath) throws Exception {
        String videoFinalfile = videoPath.replace(".mp4", "_final.mp4");
        File file = new File(videoFinalfile);
        if (file.exists()) {
            file.delete();
        }
        FFmpegFrameGrabber grabberVideo = null;
        FFmpegFrameGrabber grabberAudio = null;
        try {
            //抓取视频帧
            grabberVideo = new FFmpegFrameGrabber(videoPath);
            //抓取音频帧
            grabberAudio = new FFmpegFrameGrabber(audioPath);
            grabberVideo.start();
            grabberAudio.start();
            //获取时长,以短的文件为主进行截取
            long durationVideo = grabberVideo.getFormatContext().duration() / 1000000;
            long durationAudio = grabberAudio.getFormatContext().duration() / 1000000;
            if (durationVideo != durationAudio) {
                if (durationVideo > durationAudio) {//音频短则以音频长度为主
                    //截取视频
                    videoPath = new VedioUtils().cutVideoByDurationAndStartZ(videoPath, durationAudio);
                } else {
                    //截取音频
                    audioPath = new HandleAudioService().cutAudioByStart(audioPath, durationVideo, "wav");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (grabberVideo != null) {
                grabberVideo.stop();
                grabberVideo.release();
            }
            if (grabberAudio != null) {
                grabberAudio.stop();
                grabberAudio.release();
            }
        }
        try {
            List<String> commands = new ArrayList<>();
            commands.add("ffmpeg");
            commands.add("-i");
            commands.add(videoPath);
            commands.add("-i");
            commands.add(audioPath);
            commands.add("-c:v");
            commands.add("copy");
            commands.add("-c:a");
            commands.add("aac");
            commands.add("-strict");
            commands.add("experimental");
            commands.add("-b:a");
            commands.add("192k");
            commands.add(videoFinalfile);

            String res = FFmpegUtils.execFFmpegCommand(commands);
            System.out.println(res);
        } catch (Exception e) {
            throw new RuntimeException("ffmpeg执行异常" + e.getMessage());
        }
        return videoFinalfile;
    }

    /**
     * 通过ffmpeg将单张图片合成视频
     * ffmpeg -loop 1 -i img1.jpg -c:v libx264 -t 1 -pix_fmt yuv420p output.mp4
     * ffmpeg -loop 1 -i input_image.jpg -c:v libx264 -t 10 -r 24 -pix_fmt yuv420p output_video.mp4
     * "scale=1920:1080"
     * ffmpeg -framerate 24 -i image%03d.jpg -vf "scale=1920:1080" -c:v libx264 -profile:v high -crf 20 -pix_fmt yuv420p output.mp4
     *
     * @throws Exception
     */
    public String mergeSingleImgToVideoByFFmpeg(String imgpath, int duration, int width, int height) throws Exception {
        File file = new File(imgpath);
        String videoFinalfile = file.getParent() + File.separator + System.currentTimeMillis() + ".mp4";
        try {
            List<String> commands = new ArrayList<>();
            commands.add("ffmpeg");
            commands.add("-loop");
            commands.add("1");
            commands.add("-i");
            commands.add(imgpath);
            commands.add("-vf");
            commands.add("\"scale=" + width + ":" + height + ",setdar=dar=9/16\"");
            commands.add("-c:v");
            commands.add("libx264");
            commands.add("-t");
            commands.add("" + duration);
            commands.add("-crf");
            commands.add("20");
            commands.add("-r");
            commands.add("30");
            commands.add("-pix_fmt");
            commands.add("yuv420p");
            commands.add(videoFinalfile);

            String res = FFmpegUtils.execFFmpegCommand(commands);
            System.out.println(res);
        } catch (Exception e) {
            throw new RuntimeException("ffmpeg执行异常" + e.getMessage());
        }
        return videoFinalfile;
    }

    /**
     * 将第二个视频嵌入第一个视频
     * ffmpeg -i 1.mp4 -i 2.mp4 -filter_complex "[0:v][1:v] overlay=(W-w)/2:(H-h)/2" -c:a copy output.mp4
     */
    public String embedDoubleMp4ByDuration(String firstPath, String secondPath) {
        String finalPath = secondPath.replace(".mp4", "_embed.mp4");
        File embedFile = new File(finalPath);
        if (embedFile.exists()) {
            embedFile.delete();
        }
        try {
            List<String> commands = new ArrayList<>();
            commands.add("ffmpeg");
            commands.add("-i");
            commands.add(firstPath);
            commands.add("-i");
            commands.add(secondPath);
            commands.add("-filter_complex");
            commands.add("\"[0:v][1:v] overlay=(W-w)/2:(H-h)/2\"");
            commands.add("-c:a");
            commands.add("copy ");
            commands.add(finalPath);

            String res = FFmpegUtils.execFFmpegCommand(commands);
            System.out.println(res);
        } catch (Exception e) {
            throw new RuntimeException("ffmpeg执行异常" + e.getMessage());
        }

        return finalPath;
    }

    /**
     * 批量一键生成图签视频
     */
    public void batchMakeShortVideos(String folderPath) throws Exception {
        //先批量生成配音文件
        new HandleTTSService().handleBatchTTS(folderPath);
        //筛选文件夹
        File[] handDataList = new File(folderPath).listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.isDirectory();
            }
        });
        //遍历文件夹批量处理
        List<String> tips = new ArrayList<>();
        for (File file : handDataList) {
            try {
                String fielfolderPath = file.getAbsolutePath();
                List<File> backList = FileUtil.loopFiles(fielfolderPath, backfile -> backfile.isFile() && (backfile.getName().endsWith(".mp3") || backfile.getName().endsWith(".wav")) && backfile.getName().contains("back"));
                List<File> srcList = FileUtil.loopFiles(fielfolderPath, srcfile -> srcfile.isFile() && (srcfile.getName().endsWith(".mp3") || srcfile.getName().endsWith(".wav")) && !srcfile.getName().contains("back"));
                new MakeVideoService().makeVideoByTag(srcList.get(0).getAbsolutePath(), backList.get(0).getAbsolutePath(), file.getAbsolutePath());
            } catch (Exception e) {
                tips.add(e.toString());
            }
        }
    }

    /**
     * 批量一键生成图签视频
     */
    public void singleMakeShortVideos(String fielfolderPath) throws Exception {
        //先批量生成配音文件
        new HandleTTSService().handleBatchTTS(fielfolderPath);
        //再生成视频
        List<String> tips = new ArrayList<>();
        try {
            List<File> backList = FileUtil.loopFiles(fielfolderPath, backfile -> backfile.isFile() && (backfile.getName().endsWith(".mp3") || backfile.getName().endsWith(".wav")) && backfile.getName().contains("back"));
            List<File> srcList = FileUtil.loopFiles(fielfolderPath, srcfile -> srcfile.isFile() && (srcfile.getName().endsWith(".mp3") || srcfile.getName().endsWith(".wav")) && !srcfile.getName().contains("back"));
            new MakeVideoService().makeVideoByTag(srcList.get(0).getAbsolutePath(), backList.get(0).getAbsolutePath(), fielfolderPath);
        } catch (Exception e) {
            tips.add(e.toString());
        }
        if (tips.size() > 0) {
            throw new RuntimeException(tips.toString());
        }
    }

    /**
     * 合并多个不同的视频
     * ffmpeg -f concat -safe 0 -i file.txt -c:v libx264 -crf 20 -s 720X1280 -preset veryfast output.mp4
     */
    public void mergeMulVideos(String videoFolderPath, String ratio) throws Exception {
        List<File> mp4list = FileUtil.loopFiles(videoFolderPath, backfile -> backfile.isFile() && backfile.getName().endsWith(".mp4"));
        StringBuffer buffer = new StringBuffer();
        for (File file : mp4list) {
            buffer.append("file");
            buffer.append(" ");
            buffer.append("'");
            buffer.append(file.getAbsolutePath());
            buffer.append("'");
            buffer.append("\n");
        }
        //保存txt
        String finalpath = videoFolderPath + File.separator + "file.txt";
        String finalMp4Path = videoFolderPath + File.separator + "merged.mp4";
        //写入文件
        FileWriter writer = null;
        try {
            writer = new FileWriter(finalpath, false);
            writer.write(buffer.toString());
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (writer != null) {
                writer.flush();
                writer.close();
            }
        }
        List<String> commands = new ArrayList<>();
        commands.add("ffmpeg");
        commands.add("-f");
        commands.add("concat");
        commands.add("-safe");
        commands.add("0");
        commands.add("-i");
        commands.add(finalpath);
        commands.add("-c:v");
        commands.add("libx264");
        commands.add("-crf");
        commands.add("20");
        commands.add("-s");
        ratio = ratio.toUpperCase();
//        commands.add("720X1280");
        commands.add(ratio);
        commands.add("-preset");
        commands.add("veryfast");
        commands.add(finalMp4Path);

        String res = FFmpegUtils.execFFmpegCommand(commands);
        System.out.println(res);


    }

    /**
     * 整理待生成的长视频文件
     */
    public void handleLongVideoByTxt(String txtFolder, String backVideoFolder) throws Exception {
        List<File> txtlist = FileUtil.loopFiles(txtFolder, backfile -> backfile.isFile() && backfile.getName().endsWith(".txt"));
        List<File> mp4list = FileUtil.loopFiles(backVideoFolder, backfile -> backfile.isFile() && backfile.getName().endsWith(".mp4"));
        for (File file : txtlist) {
            //建新的文件夹
            String filename = file.getName().substring(0, file.getName().indexOf("."));
            File newfolder = new File(txtFolder + File.separator + filename);
            if (!newfolder.exists()) {
                newfolder.mkdir();
            }
            //复制txt文档到新文件夹并处理表头信息
            int index = Integer.valueOf(filename.substring(filename.indexOf("第") + 1, filename.indexOf("回")));
            String newFilename = "西游记第" + initNumstrList.get(index) + "回";
            String content = getContent(file.getAbsolutePath(), newFilename + "。");
            FileWriter writer = null;
            try {
                String finalpath = newfolder + File.separator + newFilename + ".txt";
                writer = new FileWriter(finalpath, false);
                writer.write(content);
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                if (writer != null) {
                    writer.flush();
                    writer.close();
                }
            }
            //复制背景视频到文件夹
            int randomNumber = (int) (Math.random() * (mp4list.size()));
            File videoFile = mp4list.get(randomNumber);
            //文件移动
            Path source = Paths.get(videoFile.getAbsolutePath());
            Path target = Paths.get(newfolder + File.separator + videoFile.getName());
            try {
                // 移动文件
                Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
                System.out.println("文件移动成功！");
            } catch (IOException e) {
                System.err.println("文件移动失败：" + e.getMessage());
            }

        }


    }

    /**
     * 读取文件
     */
    private String getContent(String filepath, String firstStr) throws Exception {
        InputStream inputstream = null;
        BufferedReader reader = null;
        String temp = "";
        StringBuffer result = new StringBuffer(firstStr);
        result.append("\n");
        try {
            inputstream = new FileInputStream(new File(filepath));
            reader = new BufferedReader(new InputStreamReader(inputstream));
            int num = 0;
            while ((temp = reader.readLine()) != null) {
                result.append(temp);
                result.append("\n");
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            inputstream.close();
        }
        return result.toString();
    }

    /**
     * 批量生成视频
     * @param folderPath
     */
    public void makeMulVideoByFolder(String folderPath) throws Exception {
        List<String> tips=new ArrayList<>();
        //筛选文件夹
        File[] handDataList = new File(folderPath).listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.isDirectory();
            }
        });
        for(File file:handDataList){
            try {
                new HandleLongVideoBP().makeSingleVideo(file.getAbsolutePath());
            } catch (Exception e) {
                tips.add(e.toString());
            }
        }
        if(tips.size()>0){
            throw new RuntimeException(tips.toString());
        }
    }

    /**
     * 根据时长将一个视频截取为多个短视频
     */
    public void cutVideoByDuration(String videoPath) throws Exception {
        FFmpegFrameGrabber grabberVideo = null;
        int durationVideo = 0;
        try {
            //抓取视频帧
            grabberVideo = new FFmpegFrameGrabber(videoPath);
            grabberVideo.start();
            //获取时长,以短的文件为主进行截取
             long duration= grabberVideo.getFormatContext().duration() / 1000000;
            durationVideo=Integer.parseInt(duration+"");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (grabberVideo != null) {
                grabberVideo.stop();
                grabberVideo.release();
            }
        }
        int yushu=durationVideo%300;
        int circle=0;
        if(yushu==0){
            circle= durationVideo/300;
        }else{
            circle= durationVideo/300+1;
        }
        int duration=300/60;
        for(int i=0;i<circle;i++){
            String curTimeStr="";
            String endTimeStr="";
            if(i<circle-1){
                int curTime=duration*i;
                if(curTime<10){
                    curTimeStr="0"+curTime;
                }else{
                    curTimeStr=""+curTime;
                }
                int endTime=duration*(i+1);
                if(endTime<10){
                    endTimeStr="0"+endTime;
                }else{
                    endTimeStr=""+endTime;
                }
                endTimeStr="00:"+endTimeStr+":00";
            }else{
                int curTime=duration*i;
                if(curTime<10){
                    curTimeStr="0"+curTime;
                }else{
                    curTimeStr=""+curTime;
                }
                int minus=durationVideo/60;
                int sec=durationVideo%60;
                String minuStr="";
                String secStr="";
                if(minus<10){
                    minuStr="0"+minus;
                }else{
                    minuStr=""+minus;
                }
                if(sec<10){
                    secStr="0"+sec;
                }else{
                    secStr=""+sec;
                }
                endTimeStr="00:"+minuStr+":"+secStr;
            }
            String start="00:"+curTimeStr+":00";
            String outputVideo = videoPath.replace(".mp4", "_cutvodeo_part"+i+".mp4");
            new VedioUtils().cutVideoByFFmpegByOutpath(videoPath, start, endTimeStr,outputVideo);
        }
    }

    /**
     * 写入文件
     *
     * @param buffer
     * @param finalsrt
     * @return
     * @throws Exception
     */
    private String writeFile(String buffer, String finalsrt) throws Exception {
        //写入文件
        FileWriter writer = null;
        try {
            File file = new File(finalsrt);
            if (file.exists()) {
                file.delete();
            }
            writer = new FileWriter(finalsrt, false);
            writer.write(buffer);
            return finalsrt;
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (writer != null) {
                writer.flush();
                writer.close();
            }
        }
    }
}
